package Data;

import Model.RetiradaBean;
import View.TelaPrincipal;
import java.sql.CallableStatement;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Types;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.List;
import java.util.Vector;

public class RetiradaDAO extends Conexao {

    public List listarRetiradaAsList(String lista) throws SQLException {
//        //Tratamento da lista
//        if (lista.endsWith(",")) {
//            lista = lista.substring(0, lista.length() - 2);
//        }

        String sql = "SELECT R.RETCOD, T.TITCOD, C.CLIENTECOD, R.VALOR, CASE WHEN P.PAGCOD IS NULL THEN 'Não' ELSE 'Sim' END AS PAGO FROM RETIRADA R"
                + " INNER JOIN TITULO T ON R.TITCOD = T.TITCOD"
                + " INNER JOIN CLIENTE C ON C.CLIENTECOD = R.TITCOD"
                + " INNER JOIN USUARIO U ON U.USUCOD = R.USUCOD"
                + " LEFT JOIN PAGAMENTO P ON P.RETCOD = R.RETCOD"
                + " WHERE R.RETCOD IN (" + lista + ")";

//        String sql = "SELECT R.RETCOD, T.TITCOD, C.CLIENTECOD, R.VALOR "
//                + " FROM RETIRADA R, TITULO T, CLIENTE C, USUARIO U"
//                + " WHERE R.TITCOD = T.TITCOD"
//                + " AND R.CLIENTECOD = C.CLIENTECOD"
//                + " AND R.USUCOD = U.USUCOD"
//                + " AND R.RETCOD IN (" + lista + ")";


        //Crio um array de Filmes
        List<RetiradaBean> retiradas = new ArrayList<>();

        //Pego uma conexao com o banco
        Connection conn = getConexao();

        //Preparo a consulta
        PreparedStatement ps = conn.prepareStatement(sql);

        //Executo a consulta
        ResultSet rs = ps.executeQuery();

        //Declaração dos objetos usados
        FilmeDAO filmedata = new FilmeDAO();
        ClienteDAO clientedata = new ClienteDAO();

        //Percorre todas as linhas de resultado da query
        while (rs.next()) {
            RetiradaBean retirada = new RetiradaBean();

            //Preencho as da retirada
            retirada.setCodigo(rs.getInt(1));
            retirada.setFilme(filmedata.getFilme(rs.getInt(2)));
            retirada.setCliente(clientedata.getCliente(rs.getInt(3)));
            retirada.setValor(rs.getFloat(4));
            retirada.setPago(rs.getBoolean(5));

            //Adiciona a linha ao vetor de dados
            retiradas.add(retirada);
        }

        //Fecho o preparedStatment
        ps.close();

        //Retorno os filmes encontrados
        return retiradas;

    }

    public Vector listarRetirada(String parametro, int pesquisa, int devolvido) throws SQLException {


        String sql = "SELECT R.*, CASE WHEN P.PAGCOD IS NULL THEN 'Não' ELSE 'Sim' END AS PAGO FROM RETIRADA R"
                + " INNER JOIN TITULO T ON R.TITCOD = T.TITCOD"
                + " INNER JOIN CLIENTE C ON C.CLIENTECOD = R.TITCOD"
                + " INNER JOIN USUARIO U ON U.USUCOD = R.USUCOD"
                + " LEFT JOIN PAGAMENTO P ON P.RETCOD = R.RETCOD";

//        String sql = "SELECT R.* FROM RETIRADA R, TITULO T, CLIENTE C, USUARIO U"
//                + " WHERE R.TITCOD = T.TITCOD"
//                + " AND R.CLIENTECOD = C.CLIENTECOD"
//                + " AND R.USUCOD = U.USUCOD";

        //Validação
        if (parametro == null || parametro.equalsIgnoreCase("")) {
            pesquisa = -1;
        }

        //Validação do codigo, Caso tenha algo diferente de um digito pesquisa por tudo
        if (pesquisa == 0 && !parametro.matches("\\d+")) {
            pesquisa = -1;
        }

        //Checo por qual tipo de pesquisa vai ser
        switch (pesquisa) {

            //Pesquisar por codigo da Retirada
            case 0:
                sql += " WHERE R.RETCOD = " + parametro;
                break;

            //Pesquisa por nome do filme em portugues
            case 1:
                sql += " WHERE T.TITULOPORTUGUES LIKE '%" + parametro + "%'";
                break;

            //Pesquisa por nome do filme em ingles
            case 2:
                sql += " WHERE T.TITULOORIGINAL LIKE '%" + parametro + "%'";
                break;

            //Pesquisa pelo nome DO CLIENTE
            case 3:
                sql += " WHERE C.CLIENTENOME LIKE '%" + parametro + "%'";
                break;

            //PESQUISAR PELA DATA DA RETIRADA
            case 4:
                sql += " WHERE R.DATARETIRADA = " + parametro;
                break;

            //PESQUISAR PELA DATA DE DEVOLUÇÃO
            case 5:
                sql += " WHERE R.DATADEVOLUCAO =" + parametro;
                break;

            case 6:
                sql += " WHERE U.USUNOME LIKE '%" + parametro + "%'";
                break;
        }

        //Checo filtro de devolução
        switch (devolvido) {

            //Somente devolvidos
            case 1:
                sql += " AND R.DEVOLVIDO = 'T'";
                break;

            //Somente não devolvidos
            case 2:
                sql += " AND R.DEVOLVIDO = 'F'";
                break;
        }

        //Crio um array de Filmes
        Vector dados = new Vector();

        //Pego uma conexao com o banco
        Connection conn = getConexao();

        //Preparo a consulta
        PreparedStatement ps = conn.prepareStatement(sql);

        //Executo a consulta
        ResultSet rs = ps.executeQuery();

        //Declaração dos objetos usados
        FilmeDAO filmedata = new FilmeDAO();
        ClienteDAO clientedata = new ClienteDAO();
        UsuarioDAO usuariodata = new UsuarioDAO();
        SimpleDateFormat sdf = new SimpleDateFormat("dd/MM/yyyy");

        //Percorre todas as linhas de resultado da query
        while (rs.next()) {
            Vector linha = new Vector();

            //Preencho as da retirada
            linha.addElement(rs.getObject(1));
            linha.addElement(filmedata.getFilme(rs.getInt(2)).getTitulo_portugues());
            linha.addElement(clientedata.getCliente(rs.getInt(3)).getCliente_nome());
            try {
                linha.addElement(sdf.format(rs.getDate(4)));
            } catch (Exception ex) {
                linha.addElement(rs.getObject(4).toString());
            }
            try {
                linha.addElement(sdf.format(rs.getDate(5)));
            } catch (Exception ex) {
                linha.addElement(rs.getObject(5).toString());
            }
            linha.addElement(rs.getObject(6));
            linha.addElement(rs.getString(7).equals("T") ? "Sim" : "Não");
            linha.addElement(rs.getString(9));
            linha.addElement(usuariodata.getUsuario(rs.getInt(8)).getNome());

            //Adiciona a linha ao vetor de dados
            dados.add(linha);
        }

        //Fecho o preparedStatment
        ps.close();

        //Retorno os filmes encontrados
        return dados;
    }

    public boolean isDevolvido(int id) throws SQLException {
        //Variavel de controle
        boolean resultado = false;

        //query
        String sql = "SELECT DEVOLVIDO FROM RETIRADA WHERE RETCOD = ?";

        //Validação
        if (id < 1) {
            throw new SQLException("ID Invalido!");
        }

        //Pego uma conexao com o banco
        Connection conn = getConexao();

        //Preparo a consulta
        PreparedStatement ps = conn.prepareStatement(sql);

        //Coloco os parametros na consulta
        ps.setInt(1, id);

        //Executo a consulta
        ResultSet rs = ps.executeQuery();

        //Checo se retornou algum registro
        if (rs.next()) {
            resultado = rs.getString(1).equalsIgnoreCase("T");
        } else {
            //Fecho o preparedStatment
            ps.close();
            throw new SQLException("Não retornou nenhum resultado!");
        }

        //Fecho o preparedStatment
        ps.close();

        //Retorno o resultado
        return resultado;
    }

    public boolean isPago(int id) throws SQLException {
        //Variavel de controle
        boolean resultado = false;

        //query
        String sql = "SELECT 'T' FROM PAGAMENTO WHERE RETCOD = ?";

        //Validação
        if (id < 1) {
            throw new SQLException("ID Invalido!");
        }

        //Pego uma conexao com o banco
        Connection conn = getConexao();

        //Preparo a consulta
        PreparedStatement ps = conn.prepareStatement(sql);

        //Coloco os parametros na consulta
        ps.setInt(1, id);

        //Executo a consulta
        ResultSet rs = ps.executeQuery();

        //Checo se retornou algum registro
        if (rs.next()) {
            resultado = rs.getString(1).equalsIgnoreCase("T");
        } else {
            //Fecho o preparedStatment
            ps.close();
            return false;
        }

        //Fecho o preparedStatment
        ps.close();

        //Retorno o resultado
        return resultado;
    }

    public int pegarUltimaRetirada() throws SQLException {
        //String sql
        String sql = "SELECT MAX(RETCOD) FROM RETIRADA";

        //Pego uma conexao com o banco
        Connection conn = getConexao();

        //Preparo a consulta
        PreparedStatement ps = conn.prepareStatement(sql);

        //Executo a consulta
        ResultSet rs = ps.executeQuery();

        int resultado = -1;

        //Checo se retornou algum registro
        if (rs.next()) {
            resultado = rs.getInt(1);
        } else {
            //Fecho o preparedStatment
            ps.close();
            return -1;
        }

        return resultado;
    }

    public boolean gravarRetirada(List<RetiradaBean> retiradas, boolean pagamento) throws SQLException {

        //Query
        String sql = "INSERT INTO RETIRADA (TITCOD, CLIENTECOD, DATARETIRADA, DATADEVOLUCAO, VALOR, USUCOD) VALUES (?, ?, ?, ?, ?, ?)";

        //Pego uma conexao com o banco
        Connection conn = getConexao();

        //Pra cada retirada necessaria
        for (RetiradaBean retiradaBean : retiradas) {

            //Preparo a consulta
            PreparedStatement ps = conn.prepareStatement(sql);

            //Coloco os parametros na consulta
            ps.setInt(1, retiradaBean.getFilme().getCodigo());
            ps.setInt(2, retiradaBean.getCliente().getCliente_cod());
            ps.setDate(3, retiradaBean.getData_retirada());
            ps.setDate(4, retiradaBean.getData_devolucao());
            ps.setFloat(5, retiradaBean.getValor());
            ps.setInt(6, TelaPrincipal.getUsuarioLogado().getCodigo());

            //Executo a consulta
            int resultado = ps.executeUpdate();

            //Fecho o preparedStatment
            ps.close();

            //Tratamento de erro
            if (resultado < 1) {
                throw new SQLException("Erro cadastrando Retirada");
            }

            //Caso tenha que fazer o pagamento pego o ID dessa ultima transação
            if (pagamento) {
                //Pego o codigo da retirada que acabei de gravar
                int codigo = pegarUltimaRetirada();

                if (codigo != -1) {
                    //Caso obtenho com sucesso coloco no bean
                    retiradaBean.setCodigo(codigo);
                }
            }

        }

        //Gravar pagamento dos items
        if (pagamento) {
            //query
            String sql2 = "INSERT INTO PAGAMENTO VALUES (?, GETDATE(), ?, ?)";

            //Tiro o autocommit
            conn.setAutoCommit(false);

            //Percorro todas as retiras 
            for (RetiradaBean ret : retiradas) {

                //Validação
                if (ret.getCodigo() < 1) {
                    //TODO Criar uma janelinha de erros
                    continue;
                }

                if (isDevolvido(ret.getCodigo())) {
                    //TODO Colocar na telinha de erros
                    continue;
                }

                //Preparo a consulta
                PreparedStatement ps2 = conn.prepareStatement(sql2);

                //Coloco os parametros na consulta
                ps2.setInt(1, ret.getCodigo());

                float multa = checarMulta(ret.getCodigo(), null);

                ps2.setFloat(2, multa);
                ps2.setFloat(3, ret.getValor());

                //Executo a consulta
                int resultado2 = ps2.executeUpdate();

                if (resultado2 < 0) {
                    //TODO erro
                    conn.rollback();
                    conn.setAutoCommit(true);
                    return false;
                }

                //Fecho o preparedStatment
                ps2.close();
            }

            //Tudo OK
            conn.commit();
            conn.setAutoCommit(true);
        }


        //Retorno o resultado
        return true;

    }

    public float checarMulta(int id, java.sql.Date data_devolucao) throws SQLException {
        //checar por multa
        String sql = "{CALL CALCULAR_MULTA(?, ?, ?)}";

        //Validação
        if (id < 1) {
            throw new SQLException("ID Invalido!");
        }

        //Pego uma conexao com o banco
        Connection conn = getConexao();

        //Preparo a consulta
        CallableStatement ps = conn.prepareCall(sql);

        //Coloco os parametros na consulta
        ps.setInt(1, id);
        ps.setDate(2, data_devolucao);
        ps.setFloat(3, 0);

        //registro os parametros de saida
        ps.registerOutParameter(3, Types.DECIMAL);

        //Executo a procedure
        ps.execute();

        //Pego o resultado
        float valor_multa = ps.getFloat(3);

        //Fecho o preparedStatment
        ps.close();

        //Retorno o valor da multa
        return valor_multa;
    }

    public boolean pagamentoDevolucao(int id) throws SQLException {
        //query
        String sql = "UPDATE RETIRADA SET DEVOLVIDO = 'T' WHERE RETCOD = ?";
        String sql2 = "INSERT INTO PAGAMENTO VALUES (?, GETDATE(), ?, ?)";

        //Validação
        if (id < 1) {
            throw new SQLException("ID Invalido!");
        }

        //Pego uma conexao com o banco
        Connection conn = getConexao();

        //Preparo a consulta
        PreparedStatement ps = conn.prepareStatement(sql);
        PreparedStatement ps2 = conn.prepareStatement(sql2);

        //Coloco os parametros na consulta
        ps.setInt(1, id);

        //Executo a consulta
        int resultado = ps.executeUpdate();

        //Fecho o preparedStatment
        ps.close();

        //Checo se retornou algum registro
        if (resultado > 0) {
            return true;
        } else {
            return false;
        }

    }

    public boolean pagamentoDevolucao(List<RetiradaBean> retiradas) throws SQLException {
        //query
        String sql = "UPDATE RETIRADA SET DEVOLVIDO = 'T' WHERE RETCOD = ?";
        String sql2 = "INSERT INTO PAGAMENTO VALUES (?, GETDATE(), ?, ?)";

        //Pego uma conexao com o banco
        Connection conn = getConexao();

        //Tiro o autocommit
        conn.setAutoCommit(false);

        //Percorro todas as retiras 
        for (RetiradaBean ret : retiradas) {

            //Validação
            if (ret.getCodigo() < 1) {
                //TODO Criar uma janelinha de erros
                continue;
            }

            if (isDevolvido(ret.getCodigo())) {
                //TODO Colocar na telinha de erros
                continue;
            }

            //Preparo a consulta
            PreparedStatement ps = conn.prepareStatement(sql);
            PreparedStatement ps2 = conn.prepareStatement(sql2);

            //Coloco os parametros na consulta
            ps.setInt(1, ret.getCodigo());
            ps2.setInt(1, ret.getCodigo());

            float multa = checarMulta(ret.getCodigo(), null);

            ps2.setFloat(2, multa);
            ps2.setFloat(3, ret.getValor());

            //Executo a consulta
            int resultado = ps.executeUpdate();
            int resultado2 = ps2.executeUpdate();

            if (resultado < 0 || resultado2 < 0) {
                //TODO erro
                System.out.println("Ocorreu um erro");
                conn.rollback();
                conn.setAutoCommit(true);
                return false;
            }

            //Fecho o preparedStatment
            ps.close();
            ps2.close();
        }

        //Tudo OK
        conn.commit();
        conn.setAutoCommit(true);

        return true;

    }

    public boolean devolucao(List<RetiradaBean> retiradas) throws SQLException {
        //query
        String sql = "UPDATE RETIRADA SET DEVOLVIDO = 'T' WHERE RETCOD = ?";

        //Pego uma conexao com o banco
        Connection conn = getConexao();

        //Tiro o autocommit
        conn.setAutoCommit(false);

        //Percorro todas as retiras 
        for (RetiradaBean ret : retiradas) {

            //Validação
            if (ret.getCodigo() < 1) {
                //TODO Criar uma janelinha de erros
                continue;
            }

            if (isDevolvido(ret.getCodigo())) {
                //TODO Colocar na telinha de erros
                continue;
            }

            //Preparo a consulta
            PreparedStatement ps = conn.prepareStatement(sql);

            //Coloco os parametros na consulta
            ps.setInt(1, ret.getCodigo());

            //Executo a consulta
            int resultado = ps.executeUpdate();

            if (resultado < 0) {
                //TODO erro
                conn.rollback();
                conn.setAutoCommit(true);
                return false;
            }

            //Fecho o preparedStatment
            ps.close();
        }

        //Tudo OK
        conn.commit();
        conn.setAutoCommit(true);

        return true;

    }
}
